/**
 *  VirtualStack.java : IceBird project
 *  13:41:35 
 */
package icebird.compiler.x86.old;

import icebird.metadata.BasicType;

/**
 * @author Sergey Shulepoff[Knott]
 */
public final class VirtualStack {
	
	private Item[] stack;
	private int peek;
	
	private EmitterContext context;
	
	private FPUStack fpuStack;
	
	/**
	 * Construct new virtual stack.
	 */
	public VirtualStack() {
		reset();
		fpuStack = new FPUStack();
	}
	
	public void setContext(EmitterContext c) {
		context = c;
	}
	
	/**
	 * Reset virtual stack.
	 * @return void
	 */
	public void reset() {
		stack = new Item[8];
		peek = 0;
	}
	
	/**
	 * Gets peek value.
	 * @return int
	 */
	public int getPeek() {
		return peek;
	}
	
	/**
	 * Is empty?
	 * @return boolean
	 */
	public boolean isEmpty() {
		return peek == 0;
	}
	
	private void grow() {
		Item[] newStack = new Item[stack.length * 2];
		System.arraycopy(stack, 0, newStack, 0, stack.length);
		stack = newStack;
	}
	
	public IntegerItem popInteger() {
		return (IntegerItem)pop();
	}
	
	public FloatItem popFloat() {
		return (FloatItem)pop();
	}
	
	/**
	 * Pops item from stack.
	 * @return Item
	 */
	public Item pop() {
		peek--;
		Item tmp = stack[peek];
		stack[peek] = null;
		
		return tmp;
	}
	
	/**
	 * Pops item from stack.
	 * @return Item
	 */
	public Item pop(BasicType type) {
		Item item = pop();
		if (item.getType() != type) {
			throw new RuntimeException();
		}
		
		return item;
	}
	
	/**
	 * Push item into stack.
	 * @return void
	 */
	public void push(Item item) {
		if (peek == stack.length) grow();
		
		stack[peek++] = item;
	}
	
	/**
	 * Is given item contains?
	 * @return boolean
	 */
	public final boolean contains(Item item) {
		for (int i = 0; i < peek; i++) {
			if (stack[i] == item)
				return true;
		}
		
		return false;
	}
	
	/**
	 * Push all items on actual stack.
	 * Used to end of work with method, and if no registers are available.
	 * @return int
	 */
	public final int push(EmitterContext c) {
		int i = 0;
		while ((i < peek) && (stack[i].getKind() == Item.STACK)) {
			i++;
		}
		int cnt = 0;
		while (i < peek) {
			final Item item = stack[i];

			item.push(c);
			i++;
			cnt++;
		}
		
		return cnt;
	}
	
	/**
	 * Is given item contains?
	 * @return boolean
	 */
	public final boolean uses(X86Register r) {
		for (int i = 0; i < peek; i++) {
			if (stack[i].uses(r))
				return true;
		}
		
		return false;
	}
	
	/**
	 * Visit all items.
	 * @return void
	 */
	public final void visitItems(ItemVisitor v) {
		for (int i = 0; i < peek; i++) {
			v.visit(stack[i]);
		}
	}
	
	final void push(BasicType type, X86Register.GPR gpr) {
		Item i = context.getItemFactory().createReg(context, type, gpr);
		push(i);
	}
	
	final void push64(BasicType type, X86Register.GPR lsb, X86Register.GPR msb) { 
		// TODO: Implement this
	}

	public FPUStack getFpuStack() {
		return fpuStack;
	}
}
